﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Data;
using System.Text.RegularExpressions;
using Tilver.Coder.Utility;


namespace Tilver.Coder.Core
{
    /// <summary>
    /// 代码生成枚举类
    /// </summary>
    public class CoderEnum
    {
        const string EnumRegex = "\\w*(type|set|state|status)$";
        /// <summary>
        /// 名称
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 内部使用名称
        /// </summary>
        public string CodeName { get; set; }

        /// <summary>
        /// 数据类型
        /// </summary>
        public DbType DbType { get; set; }

        /// <summary>
        /// c#类型
        /// </summary>
        public string CSharpType { get; set; }

        /// <summary>
        /// 枚举子项集合
        /// </summary>
        public List<CoderEnumItem> Items { get; set; }

        /// <summary>
        /// 描述
        /// </summary>
        public string Description { get; set; }

        public CoderEnum()
        {
            Items = new List<CoderEnumItem>();
        }
        /// <summary>
        /// 判断列是否是枚举类型
        /// </summary>
        /// <param name="dataObject"></param>
        /// <returns></returns>
        public static bool IsEnumType(CoderDataObject dataObject)
        {
            //定义的字段名符合枚举规则，可以作为枚举的数据类型，字段描述包含数据，并且以换行来区别
            return Regex.IsMatch(dataObject.CodeName, EnumRegex, RegexOptions.IgnoreCase)
                && DBTypeUtil.IsEnumType(dataObject.DbType)
                && !string.IsNullOrEmpty(dataObject.Description)
                && dataObject.Description.Contains("\n");
        }
        /// <summary>
        /// 将转换代码生成器枚举类
        /// </summary>
        /// <param name="dataObject"></param>
        /// <returns></returns>
        public static CoderEnum Parse(CoderDataObject dataObject)
        {
            if (!IsEnumType(dataObject))
                throw new ArgumentException("此列不是枚举列");

            if (string.IsNullOrEmpty(dataObject.Description))
                throw new ArgumentException("列注释不能为空");

            //枚举的格式
            //  1.xxx-[0-9]-tttt
            //    ///tttt
            //    Xxx = [0-9] ,
            //2.xx-[0-9]
            //    XX =[0-9], 
            //3.[0-9]-tttt
            //    ///tttt
            //    Item[0-9] = [0-9],
            //4.[0-9]
            //    Item[0-9] = [0-9] , 
            //5.tttt
            //    ///tttt
            //    Item[0-9],

            var result = new CoderEnum
            {
                Name = dataObject.CodeName.ToCoderEnumName(),
                CodeName = dataObject.CodeName.ToCoderEnumName(),
                DbType = dataObject.DbType,
                CSharpType = DBTypeUtil.ConvertToCSharpType(dataObject.DbType),
                Description = string.Empty,
            };

            var lines = dataObject.Description.ToCoderArrayByNewLine();
            if (lines.Length > 0)
            {
                result.Description = dataObject.Description;
            }
            var index = 0;
            foreach (var line in lines.Skip(1))
            {
                result.Items.Add(CreateEnumItem((from item in line.Split(new string[] { "-", "-" }, StringSplitOptions.RemoveEmptyEntries)
                                                 let value = item.Trim()
                                                 select value).ToArray(), index));
                index++;
            }
            return result;
        }

        public static CoderEnumItem CreateEnumItem(IList<string> values, int index)
        {
            const string numberRegex = "^[0-9]+$";
            const string enumItemPrefix = "Item";
            CoderEnumItem result;
            switch (values.Count)
            {
                case 1:
                    result = Regex.IsMatch(values[0], numberRegex)
                        ? new CoderEnumItem { Name = enumItemPrefix + values[0], Value = values[0] }
                        : new CoderEnumItem { Name = enumItemPrefix + index, Description = values[0] };
                    break;
                case 2:
                    result = Regex.IsMatch(values[0], numberRegex)
                               ? new CoderEnumItem { Name = enumItemPrefix + values[0], Value = values[0], Description = values[1] }
                               : new CoderEnumItem { Name = values[0], Value = values[1] };
                    break;
                case 3:
                    result = new CoderEnumItem { Name = values[0], Value = values[1], Description = values[2] };
                    break;
                default:
                    throw new ArgumentException();
            }

            result.CodeName = result.Name.ToCoderCodeName();
            return result;
        }
    }
}
